<?php

class ExpVariable implements ExpNumber
{
	private $name;
	private $value;
	private $isConstant;
	private $arrayRef;

	public function __construct ($name, CliMode $mode)
	{
		$this->name = $name;
		$this->arrayRef = array();

		if ($mode->getIdentifierType($name) === CliMode::ID_CONSTANT)
		{
			$this->isConstant = true;
			$this->value = $mode->getConstant($name);
		}
		else
		{
			$this->isConstant = false;
			$this->value = null;
		}
	}

	public function getValue (CliContext $context)
	{
		return CliLib::valueOf($this->get($context), $context);
	}

	public function getNumber (CliContext $context)
	{
		return CliLib::numberOf($this->get($context), $context);
	}

	public function getModeNumber (CliContext $context)
	{
		return CliLib::modeNumberOf($this->get($context), $context);
	}

	public function get (CliContext $context)
	{
		if ($this->isConstant)
		{
			return $this->value;
		}

		// Catch reference exception for giving a better error name
		try
		{
			return $context->getVariable($this->name, $this->arrayRef);
		}
		catch (CliUndefinedReferenceException $ex)
		{
			throw new CliUndefinedReferenceException(
				"Undefined variable '{$this->name}'");
		}
	}

	public function set ($value, CliContext $context)
	{
		if ($this->isConstant)
		{
			throw new CliVariableValueException(
				"Can not set value for constant '{$this->name}'");
		}

		if ($value instanceof ExpVariable && $this->name == $value->name &&
			$this->arrayRef === $value->arrayRef)
		{
			throw new CliVariableValueException(
				"Variable can not point to itself");
		}

		$context->setVariable($this->name, $this->arrayRef, $value);
	}

	public function addIndex ($index, CliContext $context)
	{
		if ($this->isConstant)
		{
			throw new CliVariableValueException(
				"Constants can not have array references");
		}

		$index = CliLib::valueOf($index, $context);
		$index = is_string($index) ? $index : CliLib::numberOf($index, $context);

		$var = new ExpVariable($this->name, $context->getMode());
		$var->arrayRef = $this->arrayRef;
		$var->arrayRef[] = $index;

		return $var;
	}

	public function __toString ()
	{
		return $this->name;
	}
}

?>